import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Scanner;
import java.util.TimeZone;

import biweekly.Biweekly;
import biweekly.ICalVersion;
import biweekly.ICalendar;
import biweekly.component.VEvent;
import biweekly.property.CalendarScale;
import biweekly.property.ExceptionDates;
import biweekly.property.Method;
import biweekly.property.RecurrenceDates;
import biweekly.util.DayOfWeek;
import biweekly.util.Duration;
import biweekly.util.Frequency;
import biweekly.util.ICalDate;
import biweekly.util.Recurrence;
import biweekly.util.com.google.ical.compat.javautil.DateIterator;

public class Oil {
    private int year, last;
    private List<ICalDate> workdays, restdays;

    public class TextUtils {
        static public boolean isEmpty(CharSequence str) {
            return str == null || str.toString().trim().length() == 0;
        }
    }

    public class DateTimeUtils {
        static public ICalDate parseICalDate(int year, String month_day) {
            if (TextUtils.isEmpty(month_day)) {
                return null;
            } else {
                month_day = month_day.trim();
                Calendar calendar = getDateZeroOClock(year, Integer.parseInt(month_day.substring(0, 2)), Integer.parseInt(month_day.substring(2, 4)));
                return new ICalDate(calendar.getTime(), false);
            }
        }

        static public List<ICalDate> parseListICalDate(int year, String string) {
            List<ICalDate> iCalDates = new ArrayList<>();
            if (!TextUtils.isEmpty(string)) {
                string = string.trim();
                for (String s : string.split(",")) {
                    iCalDates.add(parseICalDate(year, s));
                }
            }
            return iCalDates;
        }

        static public Calendar getDateZeroOClock(int year, int month, int mday) {
            Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            calendar.set(year, month - 1, mday);
            return calendar;
        }
    }

    // 构建从上年度最后一次调价开始到本年年底的工作日event
    public VEvent genWorkdayEvent() {
        VEvent event = new VEvent();

        event.setSummary(String.format("%d年工作日", year));

        Calendar calendar = DateTimeUtils.getDateZeroOClock(year - 1, 12, last);
        event.setDateStart(calendar.getTime(), false);
        event.setDuration(Duration.parse("P1D"));

        calendar = DateTimeUtils.getDateZeroOClock(year, 12, 31);

        // 周一到周五
        Recurrence recur = new Recurrence.Builder(Frequency.WEEKLY)
            .until(new ICalDate(calendar.getTime(), true))
            .workweekStarts(DayOfWeek.MONDAY)
            .byDay(DayOfWeek.MONDAY)
            .byDay(DayOfWeek.TUESDAY)
            .byDay(DayOfWeek.WEDNESDAY)
            .byDay(DayOfWeek.THURSDAY)
            .byDay(DayOfWeek.FRIDAY)
            .build();
        event.setRecurrenceRule(recur);

        // 调班
        RecurrenceDates rdate = new RecurrenceDates();
        rdate.getDates().addAll(workdays);
        event.addRecurrenceDates(rdate);

        // 调休
        ExceptionDates exdate = new ExceptionDates();
        exdate.getValues().addAll(restdays);
        event.addExceptionDates(exdate);

        return event;
    }

    // 计算油价调整日
    public List<ICalDate> calcAdjustDates(VEvent event) {
        List<ICalDate> dates = new ArrayList<ICalDate>();

        DateIterator it = event.getDateIterator(TimeZone.getTimeZone("UTC"));
        if (it.hasNext()) {
            it.next(); // 跳过上年度最后一次油价调整日
            for (int i = 1; it.hasNext(); i = (i + 1) % 10)
                if (i == 0) // 每10个工作日调整一次油价
                    dates.add(new ICalDate(it.next(), false));
                else
                    it.next();
        }

        return dates;
    }

    // 构建油价调整日event
    public VEvent genAdjustEvent(List<ICalDate> dates) {
        VEvent event = new VEvent();

        event.setSummary(String.format("油价调整（%d年）", year));

        event.setDateStart(dates.get(0), false);
        event.setDuration(Duration.parse("P1D"));

        RecurrenceDates rdate = new RecurrenceDates();
        rdate.getDates().addAll(dates);
        event.addRecurrenceDates(rdate);

        return event;
    }

    public void input() {
        //创建Scanner对象，接受从控制台输入
        Scanner scan = new Scanner(System.in);
        last = Integer.parseInt(scan.nextLine());
        year = Integer.parseInt(scan.nextLine());
        workdays = DateTimeUtils.parseListICalDate(year, scan.nextLine());
        restdays = DateTimeUtils.parseListICalDate(year, scan.nextLine());
    }

    public void output() {
        output_workday();
        output_oil();
    }

    public void output_workday() {
        ICalendar ical = new ICalendar();
        ical.setVersion(ICalVersion.V2_0);
        ical.setCalendarScale(CalendarScale.gregorian());
        ical.setMethod(new Method("PUBLISH"));
        ical.setExperimentalProperty("X-WR-CALNAME", "工作日");
        ical.setExperimentalProperty("X-WR-TIMEZONE", TimeZone.getDefault().getID());
        ical.addEvent(genWorkdayEvent()); // 工作日
        System.out.println(Biweekly.write(ical).go());

        // 将日历内容以UTF-8格式写入文件
        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("workday%d.ics", year)), "UTF-8"))) {
            writer.write(Biweekly.write(ical).go());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void output_oil() {
        ICalendar ical = new ICalendar();
        ical.setVersion(ICalVersion.V2_0);
        ical.setCalendarScale(CalendarScale.gregorian());
        ical.setMethod(new Method("PUBLISH"));
        ical.setExperimentalProperty("X-WR-CALNAME", "油价调整日");
        ical.setExperimentalProperty("X-WR-TIMEZONE", TimeZone.getDefault().getID());
        ical.addEvent(genAdjustEvent(calcAdjustDates(genWorkdayEvent()))); // 油价调整日
        System.out.println(Biweekly.write(ical).go());

        // 将日历内容以UTF-8格式写入文件
        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("oil%d.ics", year)), "UTF-8"))) {
            writer.write(Biweekly.write(ical).go());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        Oil oil = new Oil();
        oil.input();
        oil.output();
    }
}
